from bottle import route, get, post, jinja2_view, static_file
from bottle import request, response
from bottle import redirect, abort
from bottle import debug, run

view = jinja2_view

class UserSession:
    def __init__(self, cand_list=[]):
        self.waiting_lists = [[cand] for cand in cand_list]
        self.next_lists = []
        self.running_list1 = []
        self.running_list2 = []
        self.running_result = []
        
        # if more than 2 candidates, run the contest
        if len(self.waiting_lists) > 1:
            self.running_list1 = self.waiting_lists.pop()
            self.running_list2 = self.waiting_lists.pop()

    def merge_finish(self):
        # when either list is empty, the merge finishes
        return len(self.running_list1) == 0 or len(self.running_list2) == 0

    def round_finish(self):
        # when less than 2 lists in waiting_lists, this round finishes
        return len(self.waiting_lists) < 2

    def all_finish(self):
        # this merge still running
        if not self.merge_finish():
            return False

        # prepare next merge
        # step 1: add this merge's result to next round
        self.clear_merge()

        # more merge need to run
        if not self.round_finish():
            # step 2: set running lists
            self.start_merge()
            return False

        # prepare next round
        # step 1: add dangling waiting list to next round
        if len(self.waiting_lists) == 1:
            self.next_lists.append(self.waiting_lists.pop())

        # more rounds need to run
        if len(self.next_lists) > 1:
            # step 2: get next round to waiting list
            self.waiting_lists = self.next_lists
            self.next_lists = []
            self.start_merge()

            return False

        return True

    def get_candidates(self):
        """
        This method should be called when not finished
        """
        return (self.running_list1[-1], self.running_list2[-1])

    def clear_merge(self):
        nonempty_list = self.running_list1 if self.running_list1 else self.running_list2
        self.running_result.reverse()
        self.next_lists.append(nonempty_list + self.running_result)
        self.running_result = []

    def start_merge(self):
        self.running_list1 = self.waiting_lists.pop()
        self.running_list2 = self.waiting_lists.pop()

    def choose(self, bigger):
        # actually use the smaller one
        selected_list = self.running_list1 if bigger == self.running_list2[-1] else self.running_list2
        # add corresponding candidate to running_result
        selected_cand = selected_list.pop()
        self.running_result.append(selected_cand)

    def info(self):
        print '=======info======='
        print 'running list 1: ', self.running_list1
        print 'running list 2: ', self.running_list2
        print 'running result: ', self.running_result
        print 'waiting lists: ', self.waiting_lists
        print 'next lists: ', self.next_lists
        print '=======info======='

    def clear_result(self):
        pass

# session cache
SESSION = {}

@route('/')
@view('views/index.html')
def index():
    params = {}
    return params

@get('/sorting')
@view('views/sorting.html')
def sorting():
    user_id = request.get_cookie('user_id')
    if not user_id:
        import random
        user_id = str(random.getrandbits(128))
        # TBD: check existence of user_id
        response.set_cookie('user_id', user_id)
        candidates = get_all_candidates()
        SESSION[user_id] = UserSession(candidates)

    session = SESSION[user_id]
    candidates = None
    session.info()
    if not session.all_finish():
        candidates = session.get_candidates()
    params = {
            'candidates': candidates,
            }
    return params

@post('/sorting')
@view('views/sorting.html')
def sorting_post():
    # this must exist!
    user_id = request.get_cookie('user_id')
    session = SESSION[user_id]

    # process result
    choice = request.forms.choice
    session.choose(choice)

    # see if the total process is finished
    session.info()
    if session.all_finish():
        session.clear_result()
        redirect('/result')
    else:
        candidates = session.get_candidates()
        params = {
                'candidates': candidates,
                }
        return params

@route('/result')
@view('views/result.html')
def view_result():
    # this must exist
    user_id = request.get_cookie('user_id')
    session = SESSION[user_id]
    response.set_cookie('user_id', '')

    return {'ranking': session.next_lists[0]}

def get_all_candidates():
    import os
    file_names = os.listdir('static/avatars')
    return file_names

@route('/logout')
def logout():
    user_id = request.get_cookie('user_id')
    if not user_id:
        abort(403, 'You have not logged in yet!')
    else:
        response.set_cookie('user_id', '')
        redirect('/')

# static file serving
@route('/static/<filepath:path>')
def server_static(filepath):
    print filepath
    return static_file(filepath, root='./static')

debug(True)
run(reloader=True)
